#ifndef INFINITY_TERRAIN_GENERATOR_LIB_NOISE_H
#	define INFINITY_TERRAIN_GENERATOR_LIB_NOISE_H

#include "terraingenerator.h"

namespace infinity {

class TerrainGeneratorLibNoise
:	public TerrainGenerator
{
public : //! @name Construction & Destruction
	//! @{
	TerrainGeneratorLibNoise(dw::int32 radius, dw::int32 maxAltitude, dw::int32 maxDepth)
	:	m_radius(radius)
	,	m_maxAltitude(maxAltitude)
	,	m_maxDepth(maxDepth)
	{
		dwAssert(radius > 0, "Invalid radius");

		// m_surfaceConst.SetConstValue( 1.0 );
		m_surfaceHeightmapGenerator.SetSeed(2424);
		m_surfaceHeightmapGenerator.SetFrequency(1.0f / 128.0f);
		m_surfaceScaleBias.SetSourceModule(0, m_surfaceHeightmapGenerator);
		m_surfaceScaleBias.SetScale((double)m_maxAltitude * 0.5);
		m_surfaceScaleBias.SetBias((double)m_maxAltitude * 0.5);

		// m_foundationConst.SetConstValue( 1.0 );
		m_foundationHeightmapGenerator.SetSeed(4242);
		m_foundationHeightmapGenerator.SetFrequency(1.0f / 128.0f);
		m_foundationScaleBias.SetSourceModule(0, m_foundationHeightmapGenerator);
		m_foundationScaleBias.SetScale((double)maxDepth * 0.5);
		m_foundationScaleBias.SetBias((double)maxDepth * 0.5);

		m_cavernGenerator.SetSeed(12345);
		m_cavernGenerator.SetFrequency(1.0f / 128.0f);
		m_cavernScaleBias.SetSourceModule(0, m_cavernGenerator);
		m_cavernScaleBias.SetScale(0.5);
		m_cavernScaleBias.SetBias(0.45);

		m_planetShapeGenerator.SetSourceModule(0, m_surfaceScaleBias);
		m_planetShapeGenerator.SetSourceModule(1, m_foundationScaleBias);

		m_densityGenerator.SetSourceModule(0, m_planetShapeGenerator);
		m_densityGenerator.SetSourceModule(1, m_cavernScaleBias);
	}
	//! @}

public : //! @name
	//! @{
	virtual dw::byte getMaterial(const dw::maths::ivec3& coords) const
	{
		float x = (float)coords.x;
		float y = (float)coords.y;
		float z = (float)coords.z;

		if (coords.x > m_radius - 1 ||
			coords.y > m_maxAltitude ||
			coords.z > m_radius - 1)
		{
			return 0;
		}
		if (coords.x < -m_radius ||
			coords.y < m_maxDepth ||
			coords.z < -m_radius)
		{
			return 0;
		}

		float v = m_densityGenerator.GetValue(x, y, z);

		if (v > 0.95)
		{
			return 5;
		}
		else if (v > 0.7)
		{
			return 4;
		}
		else if (v > 0.5)
		{
			return 3;
		}
		else if (v > 0.0)
		{
			float vTmp;
			vTmp = m_densityGenerator.GetValue(x, y + 1, z);

			if(vTmp > 0.0f)
				return 2;
			else
				return 1;
		}
		else
		{
			return 0;
		}
	}
	//! @}

private :
	dw::int32 m_radius;

	dw::int32 m_maxAltitude;
	dw::int32 m_maxDepth;

	PlanetShape m_planetShapeGenerator;

	noise::module::Const m_surfaceConst;
	noise::module::Perlin m_surfaceHeightmapGenerator;
	noise::module::ScaleBias m_surfaceScaleBias;

	noise::module::Const m_foundationConst;
	noise::module::Perlin m_foundationHeightmapGenerator;
	noise::module::ScaleBias m_foundationScaleBias;

	noise::module::Perlin m_cavernGenerator;
	noise::module::ScaleBias m_cavernScaleBias;

	noise::module::Multiply m_densityGenerator;
};

} // namespace infinity

#endif // !INFINITY_TERRAIN_GENERATOR_LIB_NOISE_H
